#include "common.h"
#include "Special.h"

#include <algorithm>

using std::transform;

int SpecialWord::max_length = -1;

SpecialWord::SpecialWord(string name, SpecialCode code)
{
	this->name = name;
	this->code = code;
	if((signed)name.length() > max_length)
	{
		max_length = name.length();
	}
}

SpecialCode SpecialWord::getCode() const
{
	return code;
}

string SpecialWord::getName() const
{
	return name;
}

TokenExtractor Special::extractor = TokenExtractor([](char in){
	return true;
}, [](char first, ifstream& rest)->Token*{
	int size = SpecialWord::getMaxLength();
	char* buf = new char[size];

	int pos = rest.tellg();

	buf[0] = first;
	rest.get(&buf[1], size - 1);

	const SpecialWord* best = nullptr;
	for(int i = 0; i < 56; ++i)
	{
		string test = sw_table[i].getName();
		bool match = true;
		for(int j = 0; j < test.length(); ++j)
		{
			if(buf[j] != test[j])
			{
				match = false;
				break;
			}
		}
		if(match) best = &sw_table[i];
	}

	rest.seekg(0);
	for(int i = 0; i < pos; ++i) rest.get(); // TODO: figure out why the stream isn't seeking right...

	if(best) return new Special(best->getName());
	return nullptr;
});

Special::Special(string token_str) :
	Token(token_str)
{
	for(int i = 0; i < 56; ++i)
	{
		if(sw_table[i].getName() == token_str)
		{
			value = sw_table[i].getCode();
			return;
		}
	}
}

bool Special::isSpecial(string in)
{
	transform(in.begin(), in.end(), in.begin(), tolower);
	for(int i = 0; i < 56; ++i)
	{
		if(sw_table[i].getName() == in) return true;
	}
	return false;
}

string Special::print() const
{
	return getTokenString();
}

string Special::printType() const
{
	string out = getTokenString();
	transform(out.begin(), out.end(), out.begin(), toupper);
	return out;
}
